package com.suray.basic.wcs.path.core.api.impl;


import com.suray.basic.wcs.path.bo.ConnectPlanBO;
import com.suray.basic.wcs.path.bo.NodeAndPlanInfoBO;
import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.path.core.Route;
import com.suray.basic.wcs.path.core.api.NodeChoose;
import com.suray.basic.wcs.path.core.api.RouteFactory;
import com.suray.basic.wcs.path.exception.CreatePathFailedException;

import java.util.List;

/**
 * @author shaozn
 * @date 2019/2/23 - 22:35
 * @Description 路径工具类
 */
public class NodeChooseImpl implements NodeChoose {
    private RouteFactory routeFactory;
    private RouteFactory routeFactory2;

    /**
     * 选择用来最佳跨层的提升机
     *
     * @param routeFactory  第一层
     * @param routeFactory2 第二层
     */
    public NodeChooseImpl(RouteFactory routeFactory, RouteFactory routeFactory2) {
        this.routeFactory = routeFactory;
        this.routeFactory2 = routeFactory2;
    }

    /**
     * 不跨层选择最佳点
     *
     * @param routeFactory
     */
    public NodeChooseImpl(RouteFactory routeFactory) {
        this.routeFactory = routeFactory;
    }

    /**
     * 从候选节点中选择一个离当前两个点的和最优的点
     *
     * @param current        第一个点
     * @param endNode        第二个点
     * @param candidateNodes 候选点
     * @return 最合适的中间点（一般用于选择提升机）
     */
    @Override
    public Node getMostAccessibleNode(Node current, Node endNode, List<Node> candidateNodes) {
        long minPathCost = -1;
        int bestNodeIndex = -1;
        for (int i = 0; i < candidateNodes.size(); i++) {
            Node candidateNode = candidateNodes.get(i);
            Route toStartRoute;
            Route toEndRoute;
            try {
                toStartRoute = routeFactory.createRoute(current, new Node(candidateNode.getX(), candidateNode.getY(), current.getZ()), false);
                toEndRoute = routeFactory2.createRoute(endNode, new Node(candidateNode.getX(), candidateNode.getY(), endNode.getZ()), false);
            } catch (CreatePathFailedException e) {
                toStartRoute = null;
                toEndRoute = null;
            }
            if (toStartRoute == null || toEndRoute == null) {
                continue;
            }
            if (minPathCost < 0) {
                minPathCost = toStartRoute.getCost() + toEndRoute.getCost();
                bestNodeIndex = i;
            }
            if (toStartRoute.getCost() + toEndRoute.getCost() < minPathCost) {
                minPathCost = toStartRoute.getCost() + toEndRoute.getCost();
                bestNodeIndex = i;
            }
        }
        if (bestNodeIndex == -1) {
            return null;
        } else {
            return candidateNodes.get(bestNodeIndex);
        }
    }

    /**
     * 从候选列表中获取之于当前点的合适点
     *
     * @param current        当前点
     * @param candidateNodes 候选的所有可到达节点列表
     * @return
     */
    @Override
    public Node getMostAccessibleNode(Node current, List<Node> candidateNodes) {
        long minPathCost = -1;
        int bestNodeIndex = -1;
        for (int i = 0; i < candidateNodes.size(); i++) {
            Node candidateNode = candidateNodes.get(i);
            Route curPath;
            try {
                curPath = routeFactory.createRoute(current, candidateNode, false);
            } catch (CreatePathFailedException e) {
                curPath = null;
            }
            if (curPath == null) {
                continue;
            }
            if (minPathCost < 0) {
                minPathCost = curPath.getCost();
                bestNodeIndex = i;
            }
            if (curPath.getCost() < minPathCost) {
                minPathCost = curPath.getCost();
                bestNodeIndex = i;
            }
        }
        if (bestNodeIndex == -1) {
            return null;
        } else {
            return candidateNodes.get(bestNodeIndex);
        }
    }

    /**
     * 从候选列表中获取之于当前点的合适点
     *
     * @param current
     * @param nodeAndPlanGridIdBOS
     * @return
     */
    @Override
    public NodeAndPlanInfoBO getMostAccessibleNodeAndPlanGridId(Node current, List<NodeAndPlanInfoBO> nodeAndPlanGridIdBOS) {
        long minPathCost = -1;
        int bestNodeIndex = -1;
        for (int i = 0; i < nodeAndPlanGridIdBOS.size(); i++) {
            NodeAndPlanInfoBO nodeAndPlanGridIdBO = nodeAndPlanGridIdBOS.get(i);
            Route curPath;
            try {
                curPath = routeFactory.createRoute(current, nodeAndPlanGridIdBO.getNode(), false);
            } catch (CreatePathFailedException e) {
                curPath = null;
            }
            if (curPath == null) {
                continue;
            }
            long pathCost = curPath.getCost() + nodeAndPlanGridIdBO.getPlanCost();
            if (minPathCost < 0) {
                minPathCost = pathCost;
                bestNodeIndex = i;
            }
            if (pathCost < minPathCost) {
                minPathCost = pathCost;
                bestNodeIndex = i;
            }
        }
        if (bestNodeIndex == -1) {
            return null;
        } else {
            return nodeAndPlanGridIdBOS.get(bestNodeIndex);
        }
    }

    /**
     * 从候选列表中获取之于当前点的合适点
     *
     * @param connectPlanBOS
     * @param targetNode
     * @param isStartAndPre
     * @return
     */
    @Override
    public ConnectPlanBO getMostAccessibleConnectPlanBO(List<ConnectPlanBO> connectPlanBOS, Node targetNode, boolean isStartAndPre) {
        long minPathCost = -1;
        int bestNodeIndex = -1;
        for (int i = 0; i < connectPlanBOS.size(); i++) {
            ConnectPlanBO connectPlanBO = connectPlanBOS.get(i);
            Route fisrtPath;
            Route lastPath = null;
            try {
                if(connectPlanBO.getPreConnect() == null || connectPlanBO.getSufNodeConnect() == null){ // 不需要接驳
                    fisrtPath = routeFactory.createRoute(connectPlanBO.getTargetNode(), targetNode, false);
                } else {
                    if(isStartAndPre){
                        fisrtPath = routeFactory.createRoute(connectPlanBO.getTargetNode(), connectPlanBO.getPreConnect(), false);
                        lastPath = routeFactory.createRoute(connectPlanBO.getSufNodeConnect(), targetNode, false);
                    } else {
                        fisrtPath = routeFactory.createRoute(targetNode, connectPlanBO.getPreConnect(), false);
                        lastPath = routeFactory.createRoute(connectPlanBO.getSufNodeConnect(), connectPlanBO.getTargetNode(), false);
                    }
                }
            } catch (CreatePathFailedException e) {
                fisrtPath = null;
            }
            if (fisrtPath == null) {
                continue;
            }
            long pathCost = fisrtPath.getCost() + (lastPath == null ? 0 : lastPath.getCost());
            if (minPathCost < 0) {
                minPathCost = pathCost;
                bestNodeIndex = i;
            }
            if (pathCost < minPathCost) {
                minPathCost = pathCost;
                bestNodeIndex = i;
            }
        }
        if (bestNodeIndex == -1) {
            return null;
        } else {
            return connectPlanBOS.get(bestNodeIndex);
        }
    }

}
